package common

import (
	"time"
	"path/filepath"
	"os"
	"strings"
	"strconv"
	"math/rand"
	"../app/library/log"
	"io"
	"net/http"
	"fmt"
	"io/ioutil"
	"bytes"
	"mime/multipart"
	"runtime/pprof"
	"os/signal"
	"syscall"
	"encoding/json"
	"net"
	"crypto/md5"
	"regexp"
	"unicode"
)

func Uint64ToStr(id uint64) string {
	return strconv.FormatUint(id, 10)
}

func Int64ToStr(id int64) string {
	return strconv.FormatInt(id, 10)
}

func StrToUint64(str string) uint64 {
	ret, _ := strconv.ParseUint(str, 0, 64)
	return ret
}

//时间
func GetTime() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

//秒的时间戳
func GetTimeUnix() string {

	timestamp := time.Now().Unix()
	return strconv.FormatInt(timestamp, 10)
}

//纳秒的时间戳
func GetTimeUnixNano() string {

	timestamp := time.Now().UnixNano()
	return strconv.FormatInt(timestamp, 10)
}

//找出二个字符之间的内容
func BetweenStr(str, starting, ending string) string {

	s := strings.Index(str, starting)
	if s < 0 {
		return ""
	}
	s += len(starting)
	e := strings.Index(str[s:], ending)
	if e < 0 {
		return ""
	}
	return str[s : s+e]
}

// 随机休眠 最低1秒 <= max
func Sleep(min int, max int) {
	rand.Seed(time.Now().UnixNano())
	num := rand.Intn(max) + min

	time.Sleep(time.Duration(num) * time.Second)
}

//取得当前执行文件的目录
func GetCurrentDirectory() string {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}
	return strings.Replace(dir, "\\", "/", -1)
}

func CopyFile(dstName, srcName string) (written int64, err error) {
	src, err := os.Open(srcName)
	if err != nil {
		return
	}
	defer src.Close()
	dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return
	}
	defer dst.Close()
	return io.Copy(dst, src)
}

func MapDeepCopy(value interface{}) interface{} {
	if valueMap, ok := value.(map[string]interface{}); ok {
		newMap := make(map[string]interface{})
		for k, v := range valueMap {
			newMap[k] = MapDeepCopy(v)
		}

		return newMap
	} else if valueSlice, ok := value.([]interface{}); ok {
		newSlice := make([]interface{}, len(valueSlice))
		for k, v := range valueSlice {
			newSlice[k] = MapDeepCopy(v)
		}

		return newSlice
	}

	return value
}

func Substr(str string, start, length int) string {
	rs := []rune(str)
	rl := len(rs)
	end := 0

	if start < 0 {
		start = rl - 1 + start
	}
	end = start + length

	if start > end {
		start, end = end, start
	}

	if start < 0 {
		start = 0
	}
	if start > rl {
		start = rl
	}
	if end < 0 {
		end = 0
	}
	if end > rl {
		end = rl
	}

	return string(rs[start:end])
}

//HTTPGet get 请求
func HTTPGet(uri string) ([]byte, error) {
	response, err := http.Get(uri)
	if err != nil {
		return nil, err
	}

	defer response.Body.Close()
	if response.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http get error : uri=%v , statusCode=%v", uri, response.StatusCode)
	}
	return ioutil.ReadAll(response.Body)
}

//PostJSON post json 数据请求
func PostJSON(uri string, obj interface{}) ([]byte, error) {
	jsonData, err := json.Marshal(obj)
	if err != nil {
		return nil, err
	}
	jsonData = bytes.Replace(jsonData, []byte("\\u003c"), []byte("<"), -1)
	jsonData = bytes.Replace(jsonData, []byte("\\u003e"), []byte(">"), -1)
	jsonData = bytes.Replace(jsonData, []byte("\\u0026"), []byte("&"), -1)
	return PostData(uri, string(jsonData))
}

//PostJSON post json 数据请求
func PostData(uri string, jsonData string) ([]byte, error) {

	body := bytes.NewBuffer([]byte(jsonData))
	response, err := http.Post(uri, "application/json;charset=utf-8", body)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http get error : uri=%v , statusCode=%v", uri, response.StatusCode)
	}
	return ioutil.ReadAll(response.Body)
}

/**
postData := make(map[string]string)
postData["a"] = "aa"
postData["b"] = "bb"
postData["file"] = "/opt/webdata/a.php"
rep, err := common.HttpDo("http://a.com/a.php", m1)
log.Info(rep, err)
*/
func HttpDo(url string, params map[string]string) (string, error) {
	defer func() {

		if err := recover(); err != nil {
			log.Error(err)
		}

	}()
	var err error

	body := &bytes.Buffer{}
	writer := multipart.NewWriter(body)

	//存在文件则上传
	if params["file"] != "" {

		path := params["file"]
		part, err := writer.CreateFormFile("file", filepath.Base(path))
		if err != nil {
			return "", err
		}

		file, err := os.Open(path)
		if err != nil {
			return "", err
		}

		_, err = io.Copy(part, file)

		file.Close()
	}

	for key, val := range params {
		if key != "file" {
			_ = writer.WriteField(key, val)
		}
	}

	err = writer.Close()
	if err != nil {
		return "", err
	}

	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		return "", err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Connection", "Keep-Alive")
	req.Header.Set("Content-Type", writer.FormDataContentType())

	client := &http.Client{}
	resp, err := client.Do(req)

	var data []byte
	if resp != nil {

		data, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return "", err
		}
		resp.Body.Close()
	}
	return string(data), nil

}

//对代码进行性能监控( 按Ctrl+C退出监控)
func CreatCpuprofile(cpuprofile string) {
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		//pprof.WriteHeapProfile(fm)
		pprof.StartCPUProfile(f)
		//defer pprof.StopCPUProfile()
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	signal.Notify(c, syscall.SIGTERM)
	go func() {
		<-c
		log.Info("Ctrl+C to quit.")
		pprof.StopCPUProfile()
		os.Exit(1)
	}()
}
func StopCpuprofile() {
	pprof.StopCPUProfile()
}

//取得服务IP
func GetServerIp() string {

	addrs, err := net.InterfaceAddrs()
	var serviceIp = ""
	if err != nil {
		return serviceIp
	}

	for _, address := range addrs {

		// 检查ip地址判断是否回环地址
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				serviceIp = ipnet.IP.String()
			}

		}
	}
	return serviceIp
}

//md5 加密
func Md5(str string) string {
	data := []byte(str)
	has := md5.Sum(data)
	return fmt.Sprintf("%x", has)
}
func IsUrl(url string) bool {
	pattern := "((([A-Za-z]{3,9}:(?:\\/\\/)?)(?:[-;:&=\\+\\$,\\w]+@)?[A-Za-z0-9.-]+(:[0-9]+)?|(?:ww‌​w.|[-;:&=\\+\\$,\\w]+@)[A-Za-z0-9.-]+)((?:\\/[\\+~%\\/.\\w-_]*)?\\??(?:[-\\+=&;%@.\\w_]*)#?‌​(?:[\\w]*))?)";
	reg, _ := regexp.Compile(pattern)
	b := reg.MatchString(url)
	if (b == true) {
		return b
	}
	pattern = "((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)";
	reg, _ = regexp.Compile(pattern)
	b = reg.MatchString(url)
	if (b == true) {
		return b
	}
	pattern = "^((https|http|ftp|rtsp|mms)?://)?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?(([0-9]{1,3}\\.){3}[0-9]{1,3}|([0-9a-z_!~*'()-]+\\.)*([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\.[a-z]{2,6})(:[0-9]{1,4})?((/?)|(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$";
	reg, _ = regexp.Compile(pattern)
	b = reg.MatchString(url)
	if (b == true) {
		return b
	}
	pattern = `((ftp|https?)://[-\w]+(\.\w[-\w]*)+|(?i:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)+(?-i:com\b|edu\b|biz\b|gov\b|in(?:t|fo)\b|mil\b|net\b|org\b|[a-z][a-z]\b))(:\d+)?(/[^.!,?;"'<>()\[\]{}\s\x7F-\xFF]*(?:[.!,?]+[^.!,?;"'<>()\[\]{}\s\x7F-\xFF]+)*)?`
	reg, _ = regexp.Compile(pattern)
	//b = reg.MatchString(url)

	return reg.MatchString(url)
}

func JsonEscape(str string) string {
	str = strings.Replace(str, `"`, `\"`, -1)
	return str
}

// GetStrLength 返回输入的字符串的字数，汉字和中文标点算 1 个字数，英文和其他字符   1 个字数
func GetStrLength(str string) int {
	var total int
	reg := regexp.MustCompile("/·|，|。|《|》|‘|’|”|“|；|：|【|】|？|（|）|、/")

	for _, r := range str {
		if unicode.Is(unicode.Scripts["Han"], r) || reg.Match([]byte(string(r))) {
			total = total + 1
		} else {
			total += 1
		}
	}

	return total
}

func Try(fun func(), handler func(interface{})) {
	defer func() {
		if err := recover(); err != nil {
			handler(err)
		}
	}()
	fun()
}
/*
这样用

func main() {
	Try(func() {
		panic("foo")
	}, func(e interface{}) {
		print(e)
	})
}*/
